package com.xx.app.config.jwt.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.xx.app.vo.AppLoginUser;
import com.xx.common.core.redis.RedisCache;
import com.xx.common.utils.ServletUtils;
import com.xx.common.utils.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/**
 * jwt 工具类
 */
public class JwtUtils {

    protected static final long MILLIS_SECOND = 1000;

    public static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;

    private static final String CLAIM_NAME = "address";

    public static String createToken(String address, String signature, int expireTime) {
        if (StringUtils.isAnyBlank(address, signature) || expireTime <= 0) {
            throw new IllegalArgumentException("Invalid address, signature or expire time");
        }
        Date expirationDate = new Date(System.currentTimeMillis() + expireTime * MILLIS_MINUTE);
        // 加密处理密码
        Algorithm algorithm = Algorithm.HMAC256(signature);
        return JWT.create().withClaim(CLAIM_NAME, address) // 使用地址作为 claim
                .withExpiresAt(expirationDate)
                .sign(algorithm);
    }

    public static void verify(String address, String signature, String token) {
        String jwtToken = token.replace("Bearer ", "");
        Algorithm algorithm = Algorithm.HMAC256(signature);
        JWTVerifier jwtVerifier = JWT.require(algorithm).withClaim(CLAIM_NAME, address).build();
        try {
            jwtVerifier.verify(jwtToken);
        } catch (TokenExpiredException e) {
            throw new TokenExpiredException("token.expired");
        } catch (JWTVerificationException e) {
            throw new JWTVerificationException("token.error");
        }
    }

    public static String getAddress(String token) {
        try {
            String jwtToken = token.replace("Bearer ", "");
            DecodedJWT jwt = JWT.decode(jwtToken);
            return jwt.getClaim(CLAIM_NAME).asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 刷新令牌有效期
     */
    public static void refreshToken(AppLoginUser user, String address, String token, String signature, RedisCache redisCache) {
        user.setLoginTime(System.currentTimeMillis());
        user.setExpireTime(user.getLoginTime() + redisCache.expireTime * MILLIS_MINUTE);
        redisCache.setUserInfo(user.getUid(), address, token, signature, user);
    }

    public static String getAddress() {
        HttpServletRequest request = ServletUtils.getRequest();
        String jwtToken = request.getHeader("token");
        if (StringUtils.isEmpty(jwtToken)) {
            return null;
        }
        return getAddress(jwtToken);
    }

}